package no.gnet.edvd.cron;

import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import no.gnet.edvd.DataStore;
import no.gnet.edvd.engines.Engine;
import no.gnet.edvd.feed.FeedReader;
import no.gnet.edvd.feed.types.RemoteMatch;
import no.gnet.edvd.types.ActivityType;
import no.gnet.edvd.types.Event;
import no.gnet.edvd.types.MatchEvent;
import no.gnet.edvd.types.Option;
import no.gnet.edvd.types.Player;
import no.gnet.edvd.util.Mailer;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class SetResultsJob {
	

	Logger logger = Logger.getLogger(SetResultsJob.class);

	Player systemplayer = null;

	DataStore datastore;

	Engine engine;

	Mailer mailer;

	private static String apikeyencrypted = "glNtCGmKbY9eGftp6EDaKHGy4CRDZ364iO1tYJKEtHI=";

	private String baseURL = "http://football-api.com/api/";
	// =&from_date=31.08.2014&to_date=06.09.2014&match_date=31.08.2014"

	private String keypath = "/usr/edvd/edvd.jks";

	public void execute() throws Exception {
		int matchcount = 0;
		for (int day = 15; day >= 0; day--) {
			matchcount = setMatchResults(day);
		}
		logger.warn("***********");
		logger.warn("SET RESULTS DONE. NUMBER OF SET MATCHES IS " + matchcount);
		logger.warn("***********");

		if (matchcount > 0) {
			mailer.sendMail("EddeVedde", "gautesmaaland@gmail.com", "Matches have been imported",
					"Matches have been imported automatically. How many? Well, it's " + matchcount);
		}

	}

	private int setMatchResults(int day) throws Exception {
		Map<RemoteMatch, MatchEvent> matches;
		
		matches = loadMatches(day);
		int matchcount = 0;
		for (Iterator<RemoteMatch> iterator = matches.keySet().iterator(); iterator.hasNext();) {
			RemoteMatch remoteM = iterator.next();
			String result = remoteM.match_ft_score;
			String hometeam = remoteM.match_localteam_name;
			String awayteam = remoteM.match_visitorteam_name;
			if (result == null || result.isEmpty()) {
				// match not finished, ignore
				logger.debug("ignoring match, not finished: " + hometeam + "-"
						+ awayteam + ", " + remoteM.match_formatted_date);
			} else if(remoteM.match_static_id>0){
				// set results
				try {
					Event event = datastore.setMatchResult((int)remoteM.match_static_id, result);
					Option option = determineOutcome(event,result, hometeam,awayteam);
					logger.info("Tried to determine winner: " + option+ ", result was " + result);
					datastore.setWinnerForEvent(event.getId(), option.getId());
					Player player = getSystemUser();
					String text = player+ "(SetResultsJob) set winner for event " + 
							event.getId() + ", winner is option with id " + option.getId();
					datastore.logActivity(ActivityType.WINNER_SET, text, player);					
					matchcount++;
				} catch (Exception e) {
					logger.error(e);
				}
			}
		}
		return matchcount;
	}

	private Option determineOutcome(Event event, String res, String hometeam, String awayteam) {
		Option outcome=null;
		res=res.substring(1,res.length()-1);
		logger.debug("res trimmed: " + res);
		StringTokenizer st = new StringTokenizer(res,"-");
		int home=Integer.parseInt(st.nextToken());
		int away=Integer.parseInt(st.nextToken());
		if(home>away){
			outcome=event.getOptionByName(hometeam);
		} else if(home<away){
			outcome=event.getOptionByName(awayteam);
		} else {
			outcome=event.getOptionByName("draw");
		}
		return outcome;
	}

	private Map<RemoteMatch, MatchEvent> loadMatches(int indays) throws Exception {
		String url = createURL(indays);
		URLConnection urlconn = new URL(url).openConnection();
		Map<RemoteMatch, MatchEvent> matches = new FeedReader().readMatchesFromStream(urlconn.getInputStream());
		return matches;
	}

	private String createURL(int indays) throws Exception {
		String u = baseURL + "?APIKey=" + getAPIKey() + "&Action=fixtures" + "&match_date=" + daysAgo(indays);
		logger.debug("Url is " + u);
		return u;
	}

	private String daysAgo(int nOfDays) {
		DateTime today = new DateTime();
		DateTime indays = today.minusDays(nOfDays);
		DateTimeFormatter dtf = DateTimeFormat.forPattern("dd.MM.yyyy");		
		String dato = dtf.print(indays);
		logger.debug("daysAgo returns " + dato + " for " + nOfDays);
		return dato;
	}

	private String getAPIKey() throws Exception {
		KeyStore keyStore = KeyStore.getInstance("JCEKS");
		FileInputStream stream = new FileInputStream(keypath);
		keyStore.load(stream, "mercedes".toCharArray());
		Key key = keyStore.getKey("edvdkey", "mercedes".toCharArray());
		return decryptWithAESKey(apikeyencrypted, key.getEncoded());
	}

	public static void main(String[] args) {
		try {
			// new ImportJob().execute();

			// String data=args[2];
			//
			// //Encrypt Data
			// String encryptedData = encryptWithAESKey(data, key.getEncoded());
			// System.out.println("Encrypted Data : " + encryptedData);
			// //Decrypt Data
			// System.out.println("Decrypted Data : "
			// +decryptWithAESKey(encryptedData, key.getEncoded()));

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static String encryptWithAESKey(String data, byte[] key) throws NoSuchAlgorithmException,
			NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
			UnsupportedEncodingException {
		SecretKey secKey = new SecretKeySpec(key, "AES");

		Cipher cipher = Cipher.getInstance("AES");

		cipher.init(Cipher.ENCRYPT_MODE, secKey);
		byte[] newData = cipher.doFinal(data.getBytes());

		return Base64.encodeBase64String(newData);
	}

	public static String decryptWithAESKey(String inputData, byte[] key) throws NoSuchAlgorithmException,
			NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
		Cipher cipher = Cipher.getInstance("AES");
		SecretKey secKey = new SecretKeySpec(key, "AES");

		cipher.init(Cipher.DECRYPT_MODE, secKey);
		byte[] newData = cipher.doFinal(Base64.decodeBase64(inputData.getBytes()));
		return new String(newData);

	}

	private Player getSystemUser() {
		if (systemplayer == null) {
			Player player = Player.getSystemUser();
			if (!datastore.playerExists(player)) {
				systemplayer = datastore.storePlayer(player);
			} else {
				systemplayer = datastore.getPlayer(player);
			}
		}
		return systemplayer;
	}

	public Mailer getMailer() {
		return mailer;
	}

	public void setMailer(Mailer mailer) {
		this.mailer = mailer;
	}

	public Engine getEngine() {
		return engine;
	}

	public void setEngine(Engine engine) {
		this.engine = engine;
	}

	public DataStore getDatastore() {
		return datastore;
	}

	public void setDatastore(DataStore datastore) {
		this.datastore = datastore;
	}

}
